<template>
  <div class="app-container">
    <!--:inline="true"  内联布局模式,表单项横向排列,自动处理间距  -->
    <el-form :inline="true" :model="searchForm" ref="queryForm">
      <el-form-item label="用户名称" prop="username">
        <el-input
            v-model="searchForm.username"
            placeholder="请输入用户名称"
            clearable
            size="default"
            @keyup.enter="getList"
            @input="debounceSearch"
        />
      </el-form-item>
      <el-form-item label="状态" prop="status">
        <el-select v-model="searchForm.status" placeholder="用户状态" clearable style="width: 200px" @change="getList">
          <el-option label="正常" :value="1" />
          <el-option label="停用" :value="0" />
        </el-select>
      </el-form-item>
      <el-form-item>
        <el-button type="primary" icon="Search" size="default" @click="getList">搜 索</el-button>
        <el-button icon="Refresh" size="default" @click="resetQuery">重 置</el-button>
      </el-form-item>
    </el-form>

    <el-row :gutter="10">
      <el-col :span="1.5">
        <el-button type="primary" plain icon="Plus" size="default" @click="handleAdd">新增</el-button>
      </el-col>
      <el-col :span="1.5">
        <el-button type="success" plain icon="Upload" size="default" @click="handleImport">导入</el-button>
      </el-col>
      <el-col :span="1.5">
        <el-button type="warning" plain icon="Download" size="default" @click="handleExport">导出</el-button>
      </el-col>
      <el-col :span="1.5">
        <el-button type="danger" plain icon="Delete" size="default" @click="handleBatchDelete" :disabled="selectedRows.length === 0">批量删除</el-button>
      </el-col>
      <el-col :span="4">
        <el-button type="success" plain icon="SetUp" size="default" @click="goToShardingManager">分表管理</el-button>
      </el-col>
    </el-row>

    <el-table
        :data="tableData"
        ref="table"
        @row-click="handleRowClick"
        @selection-change="handleSelectionChange"
    >
      <el-table-column type="selection" align="center"/>
      <el-table-column prop="username" label="用户名"/>
      <el-table-column prop="password" label="密码" :show-overflow-tooltip="true"/>
      <el-table-column prop="email" label="邮箱"/>
      <el-table-column prop="mobilePhone" label="手机号"/>
      <el-table-column prop="status" label="用户状态">
        <template #default="scope">
          <el-switch
            v-model="scope.row.status"
            :active-value="1"
            :inactive-value="0"
            @change="handleStatusChange(scope.row)"
            :active-text="scope.row.status === 1 ? '正常' : '停用'"
            :inactive-text="scope.row.status === 0 ? '停用' : '正常'"
          />
        </template>
      </el-table-column>
      <el-table-column prop="createTime" label="创建时间">
        <template #default="scope">
          {{ parseTime(scope.row.createTime) }}
        </template>
      </el-table-column>
      <el-table-column prop="updateTime" label="更新时间">
        <template #default="scope">
          {{ parseTime(scope.row.createTime) }}
        </template>
      </el-table-column>
      <el-table-column prop="avatar" label="用户头像">
        <template #default="scope">
          <el-image
            :src="scope.row.avatar"
            :preview-src-list="[scope.row.avatar]"
            style="width: 50px; height: 50px;"
            :preview-teleported="true"
          />
        </template>
      </el-table-column>
      <el-table-column prop="gender" label="性别">
        <template #default="scope">
          {{ scope.row.gender === 1 ? '男' : '女' }}
        </template>
      </el-table-column>
      <el-table-column prop="nickname" label="用户昵称"/>
      <el-table-column prop="realName" label="真实姓名"/>
      <el-table-column prop="lastLoginTime" label="最后登录时间"/>
      <el-table-column prop="isDeleted" label="是否删除"/>
      <el-table-column prop="remark" label="备注信息"/>
      <el-table-column label="热度" align="center" width="120">
        <template slot-scope="scope">
          <el-tooltip :content="`今日热度: ${scope.row.dailyHeat || 0}, 本月热度: ${scope.row.monthlyHeat || 0}`" placement="top">
            <el-progress type="circle" :percentage="getHeatPercentage(scope.row)" :color="heatColorMap" :width="40"></el-progress>
          </el-tooltip>
        </template>
      </el-table-column>
      <el-table-column label="操作" width="360" align="center" fixed="right">
        <template #default="scope">
          <el-button link type="primary" icon="Edit" @click="handleEdit(scope.row)">编辑</el-button>
          <el-button link type="primary" icon="Plus" @click="handleAdd">新增</el-button>
          <el-button link type="warning" icon="Key" @click="handleResetPwd(scope.row)">重置密码</el-button>
          <el-popconfirm title="确定删除吗？" @confirm="handleDel(scope.row.id)">
            <template #reference><el-button link type="danger" icon="Delete">删除</el-button></template>
          </el-popconfirm>
        </template>
      </el-table-column>
    </el-table>

    <el-dialog v-model="dialogVisible" :title="form.id ? '编辑用户' : '新增用户'" width="65%">
      <el-form :model="form" :rules="rules" label-position="right" ref="form" label-width="100px">
        <el-tabs>
          <el-tab-pane label="基本信息">
            <el-row :gutter="20">
              <el-col :span="12">
        <el-form-item label="用户名" prop="username">
          <el-input v-model="form.username" placeholder="请输入用户名" clearable size="default"/>
        </el-form-item>
              </el-col>
              <el-col :span="12">
                <el-form-item label="密码" prop="password" v-if="!form.id">
                  <el-input v-model="form.password" placeholder="请输入密码" clearable size="default" show-password/>
        </el-form-item>
              </el-col>
            </el-row>

            <el-row :gutter="20">
              <el-col :span="12">
        <el-form-item label="邮箱" prop="email">
          <el-input v-model="form.email" placeholder="请输入邮箱" clearable size="default"/>
        </el-form-item>
              </el-col>
              <el-col :span="12">
        <el-form-item label="手机号" prop="mobilePhone">
          <el-input v-model="form.mobilePhone" placeholder="请输入手机号" clearable size="default"/>
        </el-form-item>
              </el-col>
            </el-row>

            <el-row :gutter="20">
              <el-col :span="12">
                <el-form-item label="用户昵称" prop="nickname">
                  <el-input v-model="form.nickname" placeholder="请输入用户昵称" clearable size="default"/>
                </el-form-item>
              </el-col>
              <el-col :span="12">
                <el-form-item label="真实姓名" prop="realName">
                  <el-input v-model="form.realName" placeholder="请输入真实姓名" clearable size="default"/>
                </el-form-item>
              </el-col>
            </el-row>

            <el-row :gutter="20">
              <el-col :span="12">
        <el-form-item label="用户状态" prop="status">
                  <el-radio-group v-model="form.status">
                    <el-radio :label="1">正常</el-radio>
                    <el-radio :label="0">停用</el-radio>
                  </el-radio-group>
                </el-form-item>
              </el-col>
              <el-col :span="12">
                <el-form-item label="性别" prop="gender">
                  <el-radio-group v-model="form.gender">
                    <el-radio :label="1">男</el-radio>
                    <el-radio :label="0">女</el-radio>
                  </el-radio-group>
        </el-form-item>
              </el-col>
            </el-row>
          </el-tab-pane>

          <el-tab-pane label="其他信息">
            <el-row :gutter="20">
              <el-col :span="12">
        <el-form-item label="创建时间" prop="createTime">
                  <el-date-picker v-model="form.createTime" type="datetime" placeholder="请选择创建时间" clearable size="default"/>
        </el-form-item>
              </el-col>
              <el-col :span="12">
        <el-form-item label="更新时间" prop="updateTime">
                  <el-date-picker v-model="form.updateTime" type="datetime" placeholder="请选择更新时间" clearable size="default"/>
        </el-form-item>
              </el-col>
            </el-row>

            <el-row :gutter="20">
              <el-col :span="24">
                <el-form-item label="用户头像" prop="avatar">
                  <FileUpload v-model="form.avatar" :user-id="form.id || 1" @update:model-value="handleAvatarUpdate" />
        </el-form-item>
              </el-col>
            </el-row>

            <el-row :gutter="20">
              <el-col :span="24">
                <el-form-item label="备注" prop="remark">
                  <el-input v-model="form.remark" type="textarea" placeholder="请输入备注信息" rows="3" />
        </el-form-item>
              </el-col>
            </el-row>
          </el-tab-pane>
        </el-tabs>
      </el-form>
      <template #footer>
        <div class="dialog-footer">
          <el-button @click="dialogVisible = false; getList();">取 消</el-button>
          <el-button type="primary" @click="save" :loading="saveLoading">确 定</el-button>
        </div>
      </template>
    </el-dialog>

    <!-- 导入对话框 -->
    <el-dialog v-model="importVisible" title="导入用户" width="40%">
      <el-upload
        class="upload-demo"
        drag
        action="/api/sysUser/import"
        :on-success="handleImportSuccess"
        :on-error="handleImportError"
        :headers="headers"
        accept=".xls,.xlsx">
        <el-icon class="el-icon--upload"><upload-filled /></el-icon>
        <div class="el-upload__text">拖拽文件到此处或<em>点击上传</em></div>
        <template #tip>
          <div class="el-upload__tip">
            请上传 .xls 或 .xlsx 格式的Excel文件，<el-button type="text" @click="downloadTemplate">下载模板</el-button>
          </div>
        </template>
      </el-upload>
    </el-dialog>

    <!-- 重置密码对话框 -->
    <el-dialog v-model="resetPwdVisible" title="重置密码" width="40%">
      <el-form :model="pwdForm" :rules="pwdRules" ref="pwdFormRef" label-width="100px">
        <el-form-item label="新密码" prop="newPassword">
          <el-input v-model="pwdForm.newPassword" placeholder="请输入新密码" show-password />
        </el-form-item>
        <el-form-item label="确认密码" prop="confirmPassword">
          <el-input v-model="pwdForm.confirmPassword" placeholder="请确认新密码" show-password />
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="this.resetPwdVisible = false">取消</el-button>
        <el-button type="primary" @click="submitResetPwd">确认</el-button>
      </template>
    </el-dialog>

    <el-pagination
        v-model="searchForm.currentPage"
        :page-size="searchForm.pageSize"
        :total="total"
        :page-sizes="[10, 20, 50, 100]"
        layout="total, sizes, prev, pager, next, jumper"
        @size-change="handleSizeChange"
        @current-change="handleCurrentChange"
    />
  </div>
</template>

<script>

import {deleteUser, listUser, saveUser, updateUser} from "@/api/user";
import request from "@/utils/request";
import FileUpload from '@/components/FileUpload/index.vue';
import { download } from "@/utils/download";
import { getUserViewCount } from '@/api/redis'

export default {
  name: "user",
  components: {
    FileUpload
  },
  data() {
    // 自定义密码确认验证
    const validateConfirmPassword = (rule, value, callback) => {
      if (value !== this.pwdForm.newPassword) {
        callback(new Error('两次输入的密码不一致'));
      } else {
        callback();
      }
    };

    return {
      validFields: {},
      searchForm: {},
      tableData: [],
      dialogVisible: false,
      importVisible: false,
      resetPwdVisible: false,
      selectedRows: [],
      form: {},
      pwdForm: {
        userId: null,
        newPassword: '',
        confirmPassword: ''
      },
      pwdRules: {
        newPassword: [
          { required: true, message: '请输入新密码', trigger: 'blur' },
          { min: 6, message: '密码长度不能少于6个字符', trigger: 'blur' }
        ],
        confirmPassword: [
          { required: true, message: '请再次输入密码', trigger: 'blur' },
          { validator: validateConfirmPassword, trigger: 'blur' }
        ]
      },
      headers: {
        'Authorization': 'Bearer ' + localStorage.getItem('token')
      },
      rules: {
        username: [{required: true, message: "请输入用户名", trigger: "blur"}],
        password: [{required: true, message: "请输入密码", trigger: "blur"}],
        email: [{required: true, message: "请输入邮箱", trigger: "blur"},
          {type: "email", message: "请输入正确的邮箱地址", trigger: "blur"} //邮箱格式验证
        ],
        mobilePhone: [{required: true, message: "请输入手机号", trigger: "blur"},
          {pattern: /^1[3-9]\d{9}$/, message: "请输入正确的手机号", trigger: "blur"}
        ],
        status: [{required: true, message: "请选择用户状态", trigger: "blur"},
          {pattern: /^[1-9]+$/, message: "请输入正确的用户状态", trigger: "blur"}
        ],
        createTime: [{required: true, message: "请选择创建时间", trigger: "blur"}],
        updateTime: [{required: true, message: "请选择更新时间", trigger: "blur"}],
        avatar: [{required: true, message: "请输入用户头像URL", trigger: "blur"}],
        gender: [{required: true, message: "请选择性别", trigger: "blur"}],
        nickname: [{required: true, message: "请输入用户昵称", trigger: "blur"}],
        realName: [{required: true, message: "请输入真实姓名", trigger: "blur"}],
      },
      total: 0,
      searchTimer: null,// 防抖定时器
      saveLoading: false,
      heatColorMap: [
        {color: '#909399', percentage: 20},
        {color: '#e6a23c', percentage: 40},
        {color: '#1989fa', percentage: 60},
        {color: '#67c23a', percentage: 80},
        {color: '#f56c6c', percentage: 100}
      ]
    };
  },
  methods: {
    // 获取用户列表
    async getList() {
      this.loading = true
      try {
        const response = await listUser(this.searchForm)
        this.tableData = response.data.records || []
        this.total = response.data.total || 0
        
        // 为每个用户获取热度数据
        for (const user of this.tableData) {
          this.getUserHeat(user)
        }
      } catch (error) {
        console.error('获取用户列表失败', error)
      } finally {
        this.loading = false
      }
    },

    async getUserHeat(user) {
      try {
        const response = await getUserViewCount(user.id)
        if (response.code === 200) {
          user.dailyHeat = response.data.dailyHeat || 0
          user.monthlyHeat = response.data.monthlyHeat || 0
          user.totalCount = response.data.totalCount || 0
        }
      } catch (error) {
        console.error('获取用户热度失败', error)
      }
    },

    getHeatPercentage(user) {
      // 基于月度热度计算百分比，假设100以上为满分
      const heat = user.monthlyHeat || 0
      return Math.min(Math.round(heat / 100 * 100), 100)
    },

    save() {
      this.$refs.form.validate(valid => {
        if (!valid) {
          this.$message.warning('请完善表单信息');
          return;
        }

        this.saveLoading = true;

        if (this.form.id) {//修改
          updateUser(this.form).then(res => {
            this.saveLoading = false;
            if (res.code === 200) {
              this.$message.success("修改成功");
              this.dialogVisible = false;
              this.getList();
            } else {
              this.$message.error(res.msg || "修改失败");
              if (res.data) {
                this.handleValidationError(res.data);
              }
            }
          }).catch(() => {
            this.saveLoading = false;
          });
        } else {//新增
          saveUser(this.form).then(res => {
            this.saveLoading = false;
            if (res.code === 200) {
              this.$message.success("保存成功");
              this.dialogVisible = false;
              this.getList();
            } else {
              this.$message.error(res.msg || "保存失败");
              if (res.data) {
                this.handleValidationError(res.data);
              }
            }
          }).catch(() => {
            this.saveLoading = false;
          });
        }
      });
    },

    // 处理验证错误
    handleValidationError(errors) {
      this.validFields = errors;
      // 将错误信息显示在对应字段下方
      Object.keys(errors).forEach(field => {
        if (this.$refs.form) {
          this.$refs.form.fields.forEach(formItem => {
            if (formItem.prop === field) {
              formItem.validateMessage = errors[field];
              formItem.validateState = 'error';
            }
          });
        }
      });
    },
    handleAdd() {
      this.dialogVisible = true;
      //
      this.form = {
        status: 1,
        gender:  1,
      };
      //将上次表单验证的消息清空
      if (this.$refs.form) {
        this.$refs.form.resetFields();
      }
    },
    handleDel(id) {
      //使用axios发出请求， 删除当前的用户
      //如果显示和关闭vue方法参数提示->settings->Inlay Hints
      deleteUser(id).then(res => {
        if (res.code === 200) {
          this.$message.success("删除成功");
          this.getList();
        } else {
          this.$message.error(res.msg || "删除失败");
        }
      })
    },
    handleEdit(row) {
      this.dialogVisible = true;
      //将上次表单验证的消息清空
      if (this.$refs.form) {
        this.$refs.form.resetFields();
      }
      this.form = JSON.stringify(JSON.stringify(row));

      //说明: 把得到的数据和form绑定
      //1.JSON.stringify(JSON.stringify(row) 是对行数据进行深拷贝
      //2.这样表格当前行的数据和弹出框的数据是独立的
      //2.这样表格当前行的数据变化,就不会影响弹出框的数据

      this.form = JSON.parse(JSON.stringify(row))
      request.get(`/api/sysUser/${row.id}`).then(res => {
        if (res.code === 200) {
          this.form = res.data;
        } else {
          this.$message.error(res.msg || '获取用户详情失败');
        }
      })
    },
    // 处理行点击
    handleRowClick(row) {
      this.$refs.table.toggleRowSelection(row);
    },
    //查询
    handleQuery() {
      this.getList();
    },
    //重置
    resetQuery() {
      this.$refs.queryForm.resetFields();
      this.searchForm = {};
      this.handleQuery();
    },
    // 分页切换
    handleSizeChange(pageSize) {
      this.searchForm.pageSize = pageSize;
      this.getList();
    },
    handleCurrentChange(currenPage) {
      this.searchForm.pageNum = currenPage;
      this.getList();
    },
    // 防抖搜索函数
    debounceSearch() {
      if (this.searchTimer) {
        clearTimeout(this.searchTimer);
      }

      //setTimeout函数 延迟触发或者是延迟加载
      //searchTimer是定时器, 是setTimeout函数的返回值, 其中记录着定时任务
      //如果用户在250毫秒期间继续输入, 那么会清除旧的定时器, 即清除尚未执行的搜索
      this.searchTimer = setTimeout(() => {
        this.getList();
      }, 250);
    },
    // 批量删除
    handleBatchDelete() {
      if (this.selectedRows.length === 0) {
        this.$message.warning('请至少选择一条记录');
        return;
      }

      const ids = this.selectedRows.map(row => row.id);
      this.$confirm('确定要批量删除选中的用户吗?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        request.delete('/api/sysUser/batchDelete', { data: ids }).then(res => {
          if (res.code === 200) {
            this.$message.success('批量删除成功');
            this.getList();
          } else {
            this.$message.error(res.msg || '批量删除失败');
          }
        });
      }).catch(() => {
        this.$message.info('已取消删除');
      });
    },

    // 导出用户
    handleExport() {
      const ids = this.selectedRows.map(function (row) {
        return row.id;
      });
      download('/api/sysUser/export', ids, '用户列表.xlsx');
    },

    // 打开导入对话框
    handleImport() {
      this.importVisible = true;
    },

    // 下载导入模板
    downloadTemplate() {
      download('/api/sysUser/downloadTemplate', {}, '用户导入模板.xlsx');
    },

    // 导入成功处理
    handleImportSuccess(response) {
      if (response.code === 200) {
        this.$message.success(response.msg || '导入成功');
        this.importVisible = false;
        this.getList();
      } else {
        this.$message.error(response.msg || '导入失败');
      }
    },

    // 导入失败处理
    handleImportError() {
      this.$message.error('导入失败');
    },

    // 处理选择变更
    handleSelectionChange(selection) {
      this.selectedRows = selection;
    },

    // 处理用户状态变更
    handleStatusChange(row) {
      request.put('/api/sysUser/changeStatus', {
        id: row.id,
        status: parseInt(row.status)
      }).then(res => {
        if (res.code === 200) {
          this.$message.success('状态修改成功');
        } else {
          // 恢复原状态
          row.status = row.status === 1 ? 0 : 1;
          this.$message.error(res.msg || '状态修改失败');
        }
      });
    },

    // 处理重置密码
    handleResetPwd(row) {
      this.resetPwdVisible = true;
      this.pwdForm.userId = row.id;
      this.pwdForm.newPassword = '';
      this.pwdForm.confirmPassword = '';
    },

    // 提交重置密码
    submitResetPwd() {
      this.$refs.pwdFormRef.validate(valid => {
        if (valid) {
          request.put('/api/sysUser/resetPwd', {
            id: this.pwdForm.userId,
            password: this.pwdForm.newPassword
          }).then(res => {
            if (res.code === 200) {
              this.$message.success('密码重置成功');
              this.resetPwdVisible = false;
            } else {
              this.$message.error(res.msg || '密码重置失败');
            }
          });
        }
      });
    },

    // 处理头像上传成功
    handleAvatarSuccess(res) {
      if (res.code === 200) {
        this.form.avatar = res.data;
        this.$message.success('头像上传成功');
      } else {
        this.$message.error(res.msg || '头像上传失败');
      }
    },

    // 处理头像值更新
    handleAvatarUpdate(newValue) {
      this.form.avatar = newValue;
    },

    // 跳转到分表管理页面
    goToShardingManager() {
      this.$router.push({ path: '/user-sharding' });
    },
  },
  created() {
    this.getList();

    // 添加ResizeObserver错误捕获
    window.addEventListener('error', (e) => {
      if (e && e.message && (
          e.message === 'ResizeObserver loop limit exceeded' ||
          e.message.includes('ResizeObserver loop completed with undelivered notifications')
      )) {
        const resizeObserverErr = e;
        resizeObserverErr.stopImmediatePropagation();
      }
    }, true);
  }
};
</script>
